﻿namespace ImageProcessing.ImageProcessor
{
    using System;
    using System.Collections.Generic;
    using System.Drawing;
    using System.Linq;
    using System.Text;

    /// <summary>
    /// TODO: Update summary.
    /// </summary>
    public static class IMG_NeighborhoodOperations
    {
        /// <summary>
        /// Applies mask to image
        /// </summary>
        /// <param name="img_Original">original image</param>
        /// <param name="img_Mask">mask to be applied</param>
        /// <returns>new buffer after applying mask</returns>
        public static Entities.IMG_Image IMG_ApplyMask(Entities.IMG_Image img_Original, double[,] img_Mask)
        {
            try
            {
                int img_Width = img_Original.Width;
                int img_Height = img_Original.Height;
                int img_Msklength = img_Mask.GetLength(0);
                int img_Padding = img_Msklength / 2;

                Entities.IMG_Image img_NewBuffer = new Entities.IMG_Image(img_Width, img_Height);

                for (int dim_I = 0; dim_I < img_Height; dim_I++)
                {
                    for (int dim_J = 0; dim_J < img_Width; dim_J++)
                    {
                        double img_Red = 0, img_Green = 0, img_Blue = 0;
                        for (int msk_I = -img_Padding; msk_I <= img_Padding; msk_I++)
                        {
                            for (int msk_J = -img_Padding; msk_J <= img_Padding; msk_J++)
                            {
                                if (dim_I + msk_I >= 0 && dim_I + msk_I < img_Height && dim_J + msk_J >= 0 && dim_J + msk_J < img_Width)
                                {
                                    img_Red += img_Original[dim_I + msk_I, dim_J + msk_J].Red * img_Mask[msk_I + img_Padding, msk_J + img_Padding];
                                    img_Green += img_Original[dim_I + msk_I, dim_J + msk_J].Green * img_Mask[msk_I + img_Padding, msk_J + img_Padding];
                                    img_Blue += img_Original[dim_I + msk_I, dim_J + msk_J].Blue * img_Mask[msk_I + img_Padding, msk_J + img_Padding];
                                }
                            }
                        }

                        img_NewBuffer[dim_I, dim_J] = new Entities.Pixel((int)img_Red, (int)img_Green, (int)img_Blue);
                    }
                }

                return img_NewBuffer;
            }
            catch (Exception img_EX)
            {
                Logger.LogException(img_EX);
                throw;
            }
        }

        /// <summary>
        /// IMs the g_ mean smoothing.
        /// </summary>
        /// <param name="img_Original">The img_ original.</param>
        /// <param name="img_maskSize">Size of the img_mask.</param>
        /// <returns>the smoothed image</returns>
        public static Entities.IMG_Image IMG_MeanSmoothing(Entities.IMG_Image img_Original, int img_maskSize)
        {
            try
            {
                double[,] img_Mask = new double[img_maskSize, img_maskSize];
                for (int i = 0; i < img_maskSize; i++)
                {
                    for (int j = 0; j < img_maskSize; j++)
                    {
                        img_Mask[i, j] = (double)1.0 / (img_maskSize * img_maskSize);
                    }
                }

                Entities.IMG_Image image = IMG_ApplyMask(img_Original, img_Mask);
                return image;
            }
            catch (Exception img_EX)
            {
                Logger.LogException(img_EX);
                throw;
            }
        }

        /// <summary>
        /// IMs the g_ gausian smoothing.
        /// </summary>
        /// <param name="img_Original">The img_ original.</param>
        /// <param name="img_sigma">The img_sigma.</param>
        /// <returns>the result image</returns>
        public static Entities.IMG_Image IMG_GausianSmoothing(Entities.IMG_Image img_Original, double img_sigma)
        {
            try
            {
                double sum = 0;
                int img_maskSize = (2 * (int)((3.7 * img_sigma) - 0.5)) + 1;
                double[,] img_Mask = new double[img_maskSize, img_maskSize];
                int x = -img_maskSize / 2;
                int y = -img_maskSize / 2;
                double factor = (double)(1 / (2 * Math.PI * img_sigma * img_sigma));
                double exp_val;
                for (int i = 0; i < img_maskSize; i++)
                {
                    x = -img_maskSize / 2;
                    for (int j = 0; j < img_maskSize; j++)
                    {
                        exp_val = ((x * x) + (y * y)) / (2 * img_sigma * img_sigma);
                        img_Mask[i, j] = (double)(factor * Math.Exp(-exp_val));
                        sum += img_Mask[i, j];
                        x++;
                    }

                    y++;
                }

                Entities.IMG_Image image = IMG_ApplyMask(img_Original, img_Mask);
                return image;
            }
            catch (Exception img_EX)
            {
                Logger.LogException(img_EX);
                throw;
            }
        }

        /// <summary>
        /// IMs the g_ point sharpening.
        /// </summary>
        /// <param name="img_Original">The img_ original.</param>
        /// <param name="img_maskSize">Size of the img_mask.</param>
        /// <returns>the result image</returns>
        public static Entities.IMG_Image IMG_PointSharpening(Entities.IMG_Image img_Original, int img_maskSize)
        {
            try
            {
                double[,] img_Mask = new double[img_maskSize, img_maskSize];
                for (int i = 0; i < img_maskSize; i++)
                {
                    for (int j = 0; j < img_maskSize; j++)
                    {
                        img_Mask[i, j] = -1;
                        if (i == img_maskSize / 2 && j == img_maskSize / 2)
                        {
                            img_Mask[i, j] = img_maskSize * img_maskSize;
                        }
                    }
                }

                Entities.IMG_Image image = IMG_ApplyMask(img_Original, img_Mask);
                return HelperFunctions.Cutoff(image);
            }
            catch (Exception img_EX)
            {
                Logger.LogException(img_EX);
                throw;
            }
        }

        /// <summary>
        /// IMs the g_ line horizontal sharpening.
        /// </summary>
        /// <param name="img_Original">The img_ original.</param>
        /// <param name="img_maskSize">Size of the img_mask.</param>
        /// <returns>the result image</returns>
        public static Entities.IMG_Image IMG_LineHorizontalSharpening(Entities.IMG_Image img_Original, int img_maskSize)
        {
            try
            {
                double[,] img_Mask = new double[img_maskSize, img_maskSize];
                int img_img_iVal = img_maskSize / 2;
                for (int j = 0; j < img_maskSize; j++)
                {
                    img_Mask[img_img_iVal, j] = 1;
                    if (j == img_maskSize - 1)
                    {
                        img_Mask[img_img_iVal, j] = -1;
                    }
                }

                Entities.IMG_Image image = IMG_ApplyMask(img_Original, img_Mask);
                return HelperFunctions.Cutoff(image);
            }
            catch (Exception img_EX)
            {
                Logger.LogException(img_EX);
                throw;
            }
        }

        /// <summary>
        /// IMs the g_ linev vertical sharpening.
        /// </summary>
        /// <param name="img_Original">The img_ original.</param>
        /// <param name="img_maskSize">Size of the img_mask.</param>
        /// <returns>the result image</returns>
        public static Entities.IMG_Image IMG_LinevVerticalSharpening(Entities.IMG_Image img_Original, int img_maskSize)
        {
            try
            {
                double[,] img_Mask = new double[img_maskSize, img_maskSize];
                int img_iVal = img_maskSize / 2;
                for (int j = 0; j < img_maskSize; j++)
                {
                    img_Mask[j, img_iVal] = 1;
                    if (j == img_maskSize - 1)
                    {
                        img_Mask[j, img_iVal] = -1;
                    }
                }

                Entities.IMG_Image image = IMG_ApplyMask(img_Original, img_Mask);
                return HelperFunctions.Cutoff(image);
            }
            catch (Exception img_EX)
            {
                Logger.LogException(img_EX);
                throw;
            }
        }

        /// <summary>
        /// IMs the g_ line diagonal1 sharpening.
        /// </summary>
        /// <param name="img_Original">The img_ original.</param>
        /// <param name="img_maskSize">Size of the img_mask.</param>
        /// <returns>the result image</returns>
        public static Entities.IMG_Image IMG_LineDiagonal1Sharpening(Entities.IMG_Image img_Original, int img_maskSize)
        {
            try
            {
                double[,] img_Mask = new double[img_maskSize, img_maskSize];
                int img_iVal = img_maskSize / 2;
                for (int i = 0; i < img_maskSize; i++)
                {
                    for (int j = 0; j < img_maskSize; j++)
                    {
                        if (i == j)
                        {
                            if (i == img_maskSize - 1)
                            {
                                img_Mask[i, j] = -1;
                            }
                            else
                            {
                                img_Mask[i, j] = 1;
                            }
                        }
                    }
                }

                Entities.IMG_Image image = IMG_ApplyMask(img_Original, img_Mask);
                return HelperFunctions.Cutoff(image);
            }
            catch (Exception img_EX)
            {
                Logger.LogException(img_EX);
                throw;
            }
        }

        /// <summary>
        /// IMs the g_ line diagonal2 sharpening.
        /// </summary>
        /// <param name="img_Original">The img_ original.</param>
        /// <param name="img_maskSize">Size of the img_mask.</param>
        /// <returns>the result image</returns>
        public static Entities.IMG_Image IMG_LineDiagonal2Sharpening(Entities.IMG_Image img_Original, int img_maskSize)
        {
            try
            {
                double[,] img_Mask = new double[img_maskSize, img_maskSize];
                int img_iVal = img_maskSize / 2;
                for (int i = 0; i < img_maskSize; i++)
                {
                    for (int j = 0; j < img_maskSize; j++)
                    {
                        if (i == j)
                        {
                            if (i == img_maskSize - 1)
                            {
                                img_Mask[i, img_maskSize - 1 - j] = -1;
                            }
                            else
                            {
                                img_Mask[i, img_maskSize - 1 - j] = 1;
                            }
                        }
                    }
                }

                Entities.IMG_Image image = IMG_ApplyMask(img_Original, img_Mask);
                return HelperFunctions.Cutoff(image);
            }
            catch (Exception img_EX)
            {
                Logger.LogException(img_EX);
                throw;
            }
        }

        /// <summary>
        /// IMs the g_ point edge detection.
        /// </summary>
        /// <param name="img_Original">The img_ original.</param>
        /// <param name="img_maskSize">Size of the img_mask.</param>
        /// <returns>the result image</returns>
        public static Entities.IMG_Image IMG_PointEdgeDetection(Entities.IMG_Image img_Original, int img_maskSize)
        {
            try
            {
                double[,] img_Mask = new double[img_maskSize, img_maskSize];
                for (int i = 0; i < img_maskSize; i++)
                {
                    for (int j = 0; j < img_maskSize; j++)
                    {
                        img_Mask[i, j] = -1;
                        if (i == img_maskSize / 2 && j == img_maskSize / 2)
                        {
                            img_Mask[i, j] = (img_maskSize * img_maskSize) - 1;
                        }
                    }
                }

                Entities.IMG_Image img_NewImg = IMG_ApplyMask(img_Original, img_Mask);
                img_NewImg = IMG_Normalize.IMG_NormalizeImage(img_NewImg);
                return img_NewImg;
            }
            catch (Exception img_EX)
            {
                Logger.LogException(img_EX);
                throw;
            }
        }

        /// <summary>
        /// IMs the g_ horizontal edge detection.
        /// </summary>
        /// <param name="img_Original">The img_ original.</param>
        /// <param name="img_maskSize">Size of the img_mask.</param>
        /// <returns>the result image</returns>
        public static Entities.IMG_Image IMG_HorizontalEdgeDetection(Entities.IMG_Image img_Original, int img_maskSize)
        {
            try
            {
                double[,] img_Mask = new double[img_maskSize, img_maskSize];
                int img_iVal = img_maskSize / 2;

                for (int i = 0; i < img_maskSize; i++)
                {
                    for (int j = 0; j < img_iVal; j++)
                    {
                        img_Mask[i, j] = img_maskSize + 2;
                    }
                }

                for (int i = 0; i < img_maskSize; i++)
                {
                    for (int j = img_iVal; j < img_maskSize; j++)
                    {
                        img_Mask[i, j] = -1 * img_maskSize;
                        if (i == j & i == img_iVal)
                        {
                            img_Mask[i, j] = 0;
                        }
                    }
                }

                Entities.IMG_Image img_NewImg = IMG_ApplyMask(img_Original, img_Mask);
                img_NewImg = IMG_Normalize.IMG_NormalizeImage(img_NewImg);
                return img_NewImg;
            }
            catch (Exception img_EX)
            {
                Logger.LogException(img_EX);
                throw;
            }
        }

        /// <summary>
        /// IMs the g_ vertical edge detection.
        /// </summary>
        /// <param name="img_Original">The img_ original.</param>
        /// <param name="img_maskSize">Size of the img_mask.</param>
        /// <returns>the result image</returns>
        public static Entities.IMG_Image IMG_VerticalEdgeDetection(Entities.IMG_Image img_Original, int img_maskSize)
        {
            try
            {
                double[,] img_Mask = new double[img_maskSize, img_maskSize];
                int img_iVal = img_maskSize / 2;

                for (int i = 0; i < img_maskSize; i++)
                {
                    for (int j = 0; j < img_iVal; j++)
                    {
                        img_Mask[j, i] = img_maskSize + 2;
                    }
                }

                for (int i = 0; i < img_maskSize; i++)
                {
                    for (int j = img_iVal; j < img_maskSize; j++)
                    {
                        img_Mask[j, i] = -1 * img_maskSize;
                        if (i == j & i == img_iVal)
                        {
                            img_Mask[j, i] = 0;
                        }
                    }
                }

                Entities.IMG_Image img_NewImg = IMG_ApplyMask(img_Original, img_Mask);
                img_NewImg = IMG_Normalize.IMG_NormalizeImage(img_NewImg);
                return img_NewImg;
            }
            catch (Exception img_EX)
            {
                Logger.LogException(img_EX);
                throw;
            }
        }

        /// <summary>
        /// IMs the g_ diagonal edge detection.
        /// </summary>
        /// <param name="img_Original">The img_ original.</param>
        /// <param name="img_maskSize">Size of the img_mask.</param>
        /// <returns>the result image</returns>
        public static Entities.IMG_Image IMG_DiagonalEdgeDetection(Entities.IMG_Image img_Original, int img_maskSize)
        {
            try
            {
                double[,] img_Mask = new double[img_maskSize, img_maskSize];
                int img_iVal = img_maskSize / 2;

                for (int i = 0; i < img_maskSize; i++)
                {
                    for (int j = 0; j < img_maskSize; j++)
                    {
                        if (i == j && i == img_iVal)
                        {
                            img_Mask[j, img_maskSize - 1 - i] = 0;
                        }
                        else if (i == j)
                        {
                            img_Mask[j, img_maskSize - 1 - i] = -1 * img_maskSize;
                        }
                        else if (j + img_maskSize - i - 1 <= img_maskSize - 2)
                        {
                            img_Mask[j, img_maskSize - 1 - i] = img_maskSize + 2;
                        }
                        else
                        {
                            img_Mask[j, img_maskSize - 1 - i] = -1 * img_maskSize;
                        }
                    }
                }

                Entities.IMG_Image img_NewImg = IMG_ApplyMask(img_Original, img_Mask);
                img_NewImg = IMG_Normalize.IMG_NormalizeImage(img_NewImg);
                return img_NewImg;
            }
            catch (Exception img_EX)
            {
                Logger.LogException(img_EX);
                throw;
            }
        }

        /// <summary>
        /// IMs the g_ diagonal2 edge detection.
        /// </summary>
        /// <param name="img_Original">The img_ original.</param>
        /// <param name="img_maskSize">Size of the img_mask.</param>
        /// <returns>the result image</returns>
        public static Entities.IMG_Image IMG_Diagonal2EdgeDetection(Entities.IMG_Image img_Original, int img_maskSize)
        {
            try
            {
                double[,] img_Mask = new double[img_maskSize, img_maskSize];
                int img_iVal = img_maskSize / 2;

                for (int i = 0; i < img_maskSize; i++)
                {
                    for (int j = 0; j < img_maskSize; j++)
                    {
                        if (i == j && i == img_iVal)
                        {
                            img_Mask[j, i] = 0;
                        }
                        else if (i == j)
                        {
                            img_Mask[j, i] = -1 * img_maskSize;
                        }
                        else if (j + img_maskSize - i - 1 <= img_maskSize - 2)
                        {
                            img_Mask[j, i] = img_maskSize + 2;
                        }
                        else
                        {
                            img_Mask[j, i] = -1 * img_maskSize;
                        }
                    }
                }

                Entities.IMG_Image img_NewImg = IMG_ApplyMask(img_Original, img_Mask);
                img_NewImg = IMG_Normalize.IMG_NormalizeImage(img_NewImg);
                return img_NewImg;
            }
            catch (Exception img_EX)
            {
                Logger.LogException(img_EX);
                throw;
            }
        }
    }
}
